{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "# pynput\n",
    "Python 操作监听鼠标、键盘  \n",
    "https://pynput.readthedocs.io/en/latest/index.html"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import os\n",
    "import time"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "### 鼠标操作"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(854, 541)\n",
      "(854, 542)\n",
      "(895, 366)\n",
      "(1070, 535)\n",
      "(409, 392)\n",
      "(354, 239)\n",
      "(754, 204)\n",
      "(1127, 350)\n",
      "(462, 713)\n",
      "(213, 320)\n",
      "屏幕鼠标分辨率： (1535, 863)\n",
      "The current pointer position is (1535, 863)\n",
      "now we have moved it to (180, 290)\n",
      "mouse.move(5, -5). The current pointer position is (185, 285)\n",
      "The current pointer position is (225, 453)\n",
      "mouse.scroll(0, 100). The current pointer position is (9, 461)\n"
     ]
    }
   ],
   "source": [
    "from pynput.mouse import Button, Controller\n",
    "mouse = Controller()\n",
    "\n",
    "# 循环查看鼠标位置\n",
    "for i in range(10):\n",
    "    print(mouse.position)\n",
    "    time.sleep(0.5)\n",
    "\n",
    "mouse.move(50000, 50000)\n",
    "print('屏幕鼠标分辨率： {}'.format(mouse.position))\n",
    "\n",
    "# 查询鼠标位置\n",
    "print('The current pointer position is {0}'.format(mouse.position))\n",
    "\n",
    "# 设置鼠标位置\n",
    "mouse.position = (180, 290)\n",
    "print('now we have moved it to {0}'.format(mouse.position))\n",
    "\n",
    "# 鼠标移动（x,y）个距离\n",
    "mouse.move(5, -5)\n",
    "print('mouse.move(5, -5). The current pointer position is {0}'.format(mouse.position))\n",
    "\n",
    "# 按下、拖动、松开 左键\n",
    "mouse.press(Button.left)\n",
    "mouse.move(0, 100)\n",
    "time.sleep(0.1)\n",
    "mouse.release(Button.left)\n",
    "print('The current pointer position is {0}'.format(mouse.position))\n",
    "time.sleep(1)\n",
    "\n",
    "# 双击\n",
    "mouse.click(Button.left, 1)\n",
    "\n",
    "# 滚轮 scroll two steps down\n",
    "# param int dx: The horizontal scroll.  水平滑块 （>0 向右滑动， <0 向左滑动）\n",
    "# param int dy: The vertical scroll.    垂直滑块 （>0 向上滑动， <0 向下滑动）\n",
    "mouse.scroll(0, 100)\n",
    "time.sleep(0.3)\n",
    "mouse.scroll(0, 100)\n",
    "time.sleep(0.3)\n",
    "mouse.scroll(0, 100)\n",
    "print('mouse.scroll(0, 100). The current pointer position is {0}'.format(mouse.position))\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "### 鼠标监听"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "----------------------------------------------------------------------------------------------------\n",
      "Scrolled down at (941, 591)\n",
      "Scrolled down at (941, 591)\n",
      "Pointer moved to (941, 591)\n",
      "Pointer moved to (941, 592)\n",
      "Pointer moved to (941, 592)\n",
      "Pointer moved to (940, 592)\n",
      "Pointer moved to (938, 592)\n",
      "Pointer moved to (934, 593)\n",
      "Pointer moved to (927, 593)\n",
      "Pointer moved to (923, 595)\n",
      "Pointer moved to (921, 595)\n",
      "Pointer moved to (919, 597)\n",
      "Pointer moved to (918, 598)\n",
      "Pointer moved to (916, 599)\n",
      "Pointer moved to (916, 600)\n",
      "Pointer moved to (915, 602)\n",
      "Pointer moved to (914, 603)\n",
      "Pointer moved to (913, 604)\n",
      "Pointer moved to (913, 605)\n",
      "Pointer moved to (912, 605)\n",
      "Pointer moved to (912, 609)\n",
      "Pointer moved to (912, 610)\n",
      "Pointer moved to (911, 612)\n",
      "Pointer moved to (910, 617)\n",
      "Pointer moved to (909, 620)\n",
      "Pointer moved to (908, 624)\n",
      "Pointer moved to (906, 625)\n",
      "Pointer moved to (905, 627)\n",
      "Pointer moved to (905, 630)\n",
      "Pointer moved to (905, 631)\n",
      "Pointer moved to (905, 632)\n",
      "Pointer moved to (905, 633)\n",
      "Pointer moved to (905, 634)\n",
      "Pointer moved to (905, 636)\n",
      "Pointer moved to (905, 637)\n",
      "Pointer moved to (905, 638)\n",
      "Pointer moved to (905, 640)\n",
      "Pointer moved to (905, 640)\n",
      "Pointer moved to (905, 642)\n",
      "Pointer moved to (907, 644)\n",
      "Pointer moved to (909, 646)\n",
      "Pointer moved to (909, 646)\n",
      "Pointer moved to (911, 648)\n",
      "Pointer moved to (912, 648)\n",
      "Pointer moved to (913, 648)\n",
      "Pointer moved to (914, 647)\n",
      "Pointer moved to (915, 647)\n",
      "Pointer moved to (915, 646)\n",
      "Pressed left at (915, 646)\n",
      "Released left at (915, 646)\n",
      "Pressed right at (915, 646)\n",
      "Released right at (915, 646)\n",
      "Pressed left at (915, 646)\n",
      "Released left at (915, 646)\n",
      "Pressed right at (915, 646)\n",
      "Released right at (915, 646)\n",
      "Pressed left at (915, 646)\n",
      "Released left at (915, 646)\n"
     ]
    }
   ],
   "source": [
    "from pynput import mouse\n",
    "\n",
    "\n",
    "# 鼠标移动\n",
    "def on_move(x, y):\n",
    "    print('Pointer moved to {}'.format((x, y)))\n",
    "\n",
    "\n",
    "# 鼠标滚轮\n",
    "def on_scroll(x, y, dx, dy):\n",
    "    print('Scrolled {0} at {1}'.format('down' if dy < 0 else 'up', (x, y)))\n",
    "\n",
    "\n",
    "# 鼠标按键\n",
    "def on_click(x, y, button, pressed):\n",
    "    print('{0} {1} at {2}'.format('Pressed' if pressed else 'Released', button.name, (x, y)))\n",
    "    # if not pressed:\n",
    "    #     # Stop listener\n",
    "    #     return False\n",
    "\n",
    "\n",
    "# # 鼠标监听\n",
    "# with mouse.Listener(on_move=on_move, on_click=on_click, on_scroll=on_scroll) as listener:\n",
    "#     # 一直监听中，直到Call pynput.mouse.Listener.stop from anywhere, raise StopException or\n",
    "#     # return False from a callback to stop the listener.\n",
    "#     listener.join()\n",
    "\n",
    "# 鼠标监听  自定义开始、结束\n",
    "listener = mouse.Listener(on_move=on_move, on_click=on_click, on_scroll=on_scroll)\n",
    "listener.start()\n",
    "print('-' * 100)\n",
    "time.sleep(10)\n",
    "listener.stop()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "### 键盘操作"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from pynput.keyboard import Key, Controller\n",
    "\n",
    "# pynput 说明文档  https://pynput.readthedocs.io/en/latest/index.html\n",
    "# Key 枚举类别：\n",
    "#     alt、alt_l、alt_r、backspace、caps_lock、cmd、cmd_r、ctrl、ctrl_l、ctrl_r、delete、down、end、enter、esc、\n",
    "#     f1、f2、f3、f4、f5、f6、f7、f8、f9、f10、f11、f12、f13、f14、f15、f16、f17、f18、f19、f20、\n",
    "#     home、left、page_down、page_up、right、shift、shift_r、space、tab、up、\n",
    "#     media_play_pause、media_volume_mute、media_volume_down、media_volume_up、media_previous、media_next、\n",
    "#     insert、menu、num_lock、pause、print_screen、scroll_lock\n",
    "\n",
    "time.sleep(3)\n",
    "keyboard = Controller()\n",
    "\n",
    "# 截取屏幕\n",
    "keyboard.press(Key.print_screen)\n",
    "keyboard.release(Key.print_screen)\n",
    "\n",
    "# Type a lower case A; this will work even if no key on the\n",
    "# physical keyboard is labelled 'A'\n",
    "keyboard.press('a')\n",
    "keyboard.release('a')\n",
    "\n",
    "# Type two upper case As\n",
    "keyboard.press('A')\n",
    "keyboard.release('A')\n",
    "\n",
    "# Ctrl + key\n",
    "with keyboard.pressed(Key.ctrl):\n",
    "    keyboard.press('a')\n",
    "    keyboard.release('a')\n",
    "\n",
    "with keyboard.pressed(Key.ctrl):\n",
    "    keyboard.press('c')\n",
    "    keyboard.release('c')\n",
    "\n",
    "keyboard.press(Key.right)\n",
    "keyboard.release(Key.right)\n",
    "keyboard.press(Key.enter)\n",
    "keyboard.release(Key.enter)\n",
    "with keyboard.pressed(Key.ctrl):\n",
    "    keyboard.press('v')\n",
    "    keyboard.release('v')\n",
    "\n",
    "# shift + key\n",
    "with keyboard.pressed(Key.shift):\n",
    "    keyboard.press('1')    # !\n",
    "    keyboard.release('1')  # !\n",
    "\n",
    "# Type 'Hello World' using the shortcut type method\n",
    "keyboard.type('Hello World\\n')\n",
    "keyboard.type('你好！')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "aA\n",
    "aA!Hello World\n",
    "你好！"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "### 后台截图"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from PIL import ImageGrab\n",
    "from pynput.keyboard import Key, Controller\n",
    "\n",
    "# 保存屏幕截图\n",
    "def save_prt_sc(path, img_type='BMP', sleep=0.5):\n",
    "    \"\"\"\n",
    "    import os\n",
    "    import time\n",
    "    from PIL import ImageGrab\n",
    "\n",
    "    :param path:      截取图片保存文件夹\n",
    "    :param img_type:  图片类别， BMP、PNG\n",
    "    :param sleep:     截取暂停时间\n",
    "    :return:\n",
    "    \"\"\"\n",
    "    keyboard = Controller()\n",
    "    \n",
    "    os.makedirs(path, exist_ok=True)\n",
    "    keyboard.press(Key.print_screen)\n",
    "    keyboard.release(Key.print_screen)\n",
    "    time.sleep(sleep)\n",
    "    try:\n",
    "        # 从剪切板读取屏幕截图\n",
    "        im = ImageGrab.grabclipboard()\n",
    "\n",
    "        # 保存图片\n",
    "        # img_name = '{}-{:05d}'.format(time.strftime('%Y%m%d%H%M%S', time.localtime(time.time())), i)\n",
    "        img_name = '{:.5f}'.format(time.time())\n",
    "\n",
    "        if img_type == 'BMP':\n",
    "            im.save(os.path.join(path, '{}.bmp'.format(img_name)), 'BMP')\n",
    "        else:\n",
    "            im.save(os.path.join(path, '{}.png'.format(img_name)), 'PNG')\n",
    "\n",
    "    except Exception as error:\n",
    "        del error\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n",
      "1\n",
      "2\n",
      "3\n",
      "4\n",
      "5\n",
      "6\n",
      "7\n",
      "8\n",
      "9\n"
     ]
    }
   ],
   "source": [
    "for i in range(10):\n",
    "    print(i)\n",
    "    # 保存屏幕截图\n",
    "    save_prt_sc(r'D:\\_temp\\_PrtSc2', img_type='PNG', sleep=0.5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "### 键盘监听"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Key.enter released\n",
      "Key.shift_r released\n",
      "alt_pressed() None\n",
      "alt_pressed() None\n",
      "----   'a'\n",
      "====   65\n",
      "alphanumeric key a pressed\n",
      "'a' released\n",
      "alt_pressed() None\n",
      "alt_pressed() None\n",
      "----   Key.shift\n",
      "special key Key.shift pressed\n",
      "alt_pressed() None\n",
      "alt_pressed() None\n",
      "----   'A'\n",
      "====   65\n",
      "alphanumeric key A pressed\n",
      "Key.shift released\n",
      "'a' released\n",
      "alt_pressed() None\n",
      "alt_pressed() None\n",
      "----   Key.ctrl_l\n",
      "special key Key.ctrl_l pressed\n",
      "alt_pressed() None\n",
      "alt_pressed() None\n",
      "----   '\\x01'\n",
      "====   65\n",
      "alphanumeric key \u0001 pressed\n",
      "Key.ctrl_l released\n",
      "'a' released\n",
      "alt_pressed() None\n",
      "alt_pressed() None\n",
      "----   Key.alt_l\n",
      "special key Key.alt_l pressed\n",
      "alt_pressed() None\n",
      "alt_pressed() None\n",
      "----   'a'\n",
      "====   65\n",
      "alphanumeric key a pressed\n",
      "'a' released\n",
      "Key.alt_l released\n"
     ]
    }
   ],
   "source": [
    "from pynput import keyboard\n",
    "\n",
    "\n",
    "def on_press(key):\n",
    "    print('alt_pressed()', keyboard.Controller.alt_pressed.fset)\n",
    "    print('alt_pressed()', keyboard.Controller.alt_pressed.fdel)\n",
    "\n",
    "    try:\n",
    "        print('----  ', key)\n",
    "        print('====  ', key.vk)  # virtual key code\n",
    "        print('alphanumeric key {0} pressed'.format(key.char))\n",
    "    except AttributeError:\n",
    "        print('special key {0} pressed'.format(key))\n",
    "\n",
    "\n",
    "def on_release(key):\n",
    "    print('{0} released'.format(key))\n",
    "    # if key == keyboard.Key.esc:\n",
    "    #     # Stop listener\n",
    "    #     return False\n",
    "\n",
    "\n",
    "# Collect events until released\n",
    "# with keyboard.Listener(on_press=on_press, on_release=on_release) as listener:\n",
    "#     listener.join()\n",
    "\n",
    "# ...or, in a non-blocking fashion:\n",
    "listener = keyboard.Listener(  on_press=on_press,  on_release=on_release)\n",
    "listener.start()\n",
    "time.sleep(10)\n",
    "listener.stop()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<ctrl>+<alt>+h pressed\n",
      "<ctrl>+<alt>+i pressed\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Unhandled exception in listener callback\n",
      "Traceback (most recent call last):\n",
      "  File \"C:\\Program Files\\Anaconda3\\lib\\site-packages\\pynput\\_util\\__init__.py\", line 162, in inner\n",
      "    return f(self, *args, **kwargs)\n",
      "  File \"C:\\Program Files\\Anaconda3\\lib\\site-packages\\pynput\\keyboard\\_win32.py\", line 274, in _process\n",
      "    self.on_press(key)\n",
      "  File \"C:\\Program Files\\Anaconda3\\lib\\site-packages\\pynput\\_util\\__init__.py\", line 78, in inner\n",
      "    if f(*args) is False:\n",
      "  File \"C:\\Program Files\\Anaconda3\\lib\\site-packages\\pynput\\keyboard\\__init__.py\", line 244, in _on_press\n",
      "    hotkey.press(self.canonical(key))\n",
      "  File \"C:\\Program Files\\Anaconda3\\lib\\site-packages\\pynput\\keyboard\\__init__.py\", line 203, in press\n",
      "    self._on_activate()\n",
      "  File \"<ipython-input-2-1747034a74f4>\", line 12, in hot_keys_stop\n",
      "    raise MyException()\n",
      "MyException\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<ctrl>+<alt>+s was pressed\n"
     ]
    }
   ],
   "source": [
    "from pynput import keyboard\n",
    "\n",
    "def on_activate_h():\n",
    "    print('<ctrl>+<alt>+h pressed')\n",
    "\n",
    "def on_activate_i():\n",
    "    print('<ctrl>+<alt>+i pressed')\n",
    "\n",
    "class MyException(Exception): pass\n",
    "\n",
    "def hot_keys_stop():\n",
    "    raise MyException() \n",
    "\n",
    "with keyboard.GlobalHotKeys({\n",
    "        '<ctrl>+<alt>+s': hot_keys_stop,\n",
    "        '<ctrl>+<alt>+h': on_activate_h,\n",
    "        '<ctrl>+<alt>+i': on_activate_i}) as h:\n",
    "    try:\n",
    "        h.join()\n",
    "    except MyException as e:\n",
    "        print('<ctrl>+<alt>+s was pressed')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "### 鼠标键盘操作监控器"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# -*- coding: utf-8 -*-\n",
    "\"\"\"\n",
    "******* 文档说明 ******\n",
    "\n",
    "鼠标键盘操作监控器\n",
    "\n",
    "# 当前项目: Cifar10-Classification\n",
    "# 创建时间: 2020/2/12 20:21\n",
    "# 开发作者: vincent\n",
    "# 创建平台: PyCharm Community Edition\n",
    "# 版    本: V1.0\n",
    "\"\"\"\n",
    "import os\n",
    "import time\n",
    "import logging\n",
    "from pynput import mouse\n",
    "from pynput import keyboard\n",
    "\n",
    "\n",
    "# 日志文件设置，可将日志文件分别打印到前端及日志中\n",
    "def logger_set(path, f_level='DEBUG', s_level='DEBUG', name='main'):\n",
    "    \"\"\"\n",
    "    :param path:      日志保存路径\n",
    "    :param s_level:   控制台输出的日志级别默认为 DEBUG   # DEBUG，INFO，WARNING，ERROR，CRITICAL\n",
    "    :param f_level:   日志文件输出的日志级别默认为 DEBUG   # DEBUG，INFO，WARNING，ERROR，CRITICAL\n",
    "    :param name:      日志名称，默认为 'main'\n",
    "    :return:          日志配置文件设置，无返回\n",
    "    \"\"\"\n",
    "\n",
    "    # 创建一个logger\n",
    "    logger = logging.getLogger(name)\n",
    "    logger.setLevel(logging.DEBUG)\n",
    "\n",
    "    # 创建一个handler，用于写入日志文件 【默认为 DEBUG 级别】\n",
    "    fh = logging.FileHandler(path, encoding='utf-8')\n",
    "    if f_level == 'INFO':\n",
    "        fh.setLevel(logging.INFO)  # DEBUG，INFO，WARNING，ERROR，CRITICAL\n",
    "    elif f_level == 'WARNING':\n",
    "        fh.setLevel(logging.WARNING)  # DEBUG，INFO，WARNING，ERROR，CRITICAL\n",
    "    elif f_level == 'ERROR':\n",
    "        fh.setLevel(logging.ERROR)  # DEBUG，INFO，WARNING，ERROR，CRITICAL\n",
    "    elif f_level == 'CRITICAL':\n",
    "        fh.setLevel(logging.CRITICAL)  # DEBUG，INFO，WARNING，ERROR，CRITICAL\n",
    "    else:\n",
    "        fh.setLevel(logging.DEBUG)  # DEBUG，INFO，WARNING，ERROR，CRITICAL\n",
    "\n",
    "    # 创建一个handler，用于输出到控制台 【Level 可由用户设置，默认为 DEBUG 级别】\n",
    "    sh = logging.StreamHandler()\n",
    "\n",
    "    if s_level == 'INFO':\n",
    "        sh.setLevel(logging.INFO)  # DEBUG，INFO，WARNING，ERROR，CRITICAL\n",
    "    elif s_level == 'WARNING':\n",
    "        sh.setLevel(logging.WARNING)  # DEBUG，INFO，WARNING，ERROR，CRITICAL\n",
    "    elif s_level == 'ERROR':\n",
    "        sh.setLevel(logging.ERROR)  # DEBUG，INFO，WARNING，ERROR，CRITICAL\n",
    "    elif s_level == 'CRITICAL':\n",
    "        sh.setLevel(logging.CRITICAL)  # DEBUG，INFO，WARNING，ERROR，CRITICAL\n",
    "    else:\n",
    "        sh.setLevel(logging.DEBUG)  # DEBUG，INFO，WARNING，ERROR，CRITICAL\n",
    "\n",
    "    # 定义handler的输出格式\n",
    "    # formatter = '%(asctime)s %(name)s %(filename)s %(funcName)s %(lineno)4d %(levelname)-8s:  %(message)s'\n",
    "    formatter = '%(asctime)s %(levelname)-8s: %(message)s'\n",
    "    fh.setFormatter(logging.Formatter(formatter))\n",
    "\n",
    "    formatter = '%(asctime)s %(levelname)-8s: %(message)s'\n",
    "    sh.setFormatter(logging.Formatter(formatter))\n",
    "\n",
    "    # 给logger添加handler\n",
    "    logger.addHandler(fh)\n",
    "    logger.addHandler(sh)\n",
    "\n",
    "\n",
    "# 鼠标键盘监控器\n",
    "class OperationGhost(object):\n",
    "    key_code = {48: '0', 49: '1', 50: '2', 51: '3', 52: '4', 53: '5', 54: '6', 55: '7', 56: '8', 57: '9', 65: 'A',\n",
    "                66: 'B', 67: 'C', 68: 'D', 69: 'E', 70: 'F', 71: 'G', 72: 'H', 73: 'I', 74: 'J', 75: 'K', 76: 'L',\n",
    "                77: 'M', 78: 'N', 79: 'O', 80: 'P', 81: 'Q', 82: 'R', 83: 'S', 84: 'T', 85: 'U', 86: 'V', 87: 'W',\n",
    "                88: 'X', 89: 'Y', 90: 'Z', 96: '0', 97: '1', 98: '2', 99: '3', 100: '4', 101: '5', 102: '6', 103: '7',\n",
    "                104: '8', 105: '9', 106: '*', 107: '+', 108: 'Enter', 109: '-', 110: '.', 111: '/', 112: 'F1',\n",
    "                113: 'F2', 114: 'F3', 115: 'F4', 116: 'F5', 117: 'F6', 118: 'F7', 119: 'F8', 120: 'F9', 121: 'F10',\n",
    "                122: 'F11', 123: 'F12', 8: 'BackSpace', 9: 'Tab', 12: 'Clear', 13: 'Enter', 16: 'Shift', 17: 'Control',\n",
    "                18: 'Alt', 20: 'Cape Lock', 27: 'Esc', 32: 'Spacebar', 33: 'Page Up', 34: 'Page Down', 35: 'End',\n",
    "                36: 'Home', 37: 'Left Arrow', 38: 'Up Arrow', 39: 'Right Arrow', 40: 'Dw Arrow', 45: 'Insert',\n",
    "                46: 'Delete', 144: 'Num Lock', 186: ';:', 187: '=+', 188: ',<', 189: '-_', 190: '.>', 191: '/?',\n",
    "                192: '`~', 219: '[{', 220: '\\|', 221: ']}', 222: ''''\"'''}\n",
    "\n",
    "    def __init__(self, log_path=None):\n",
    "        # 开始时间\n",
    "        self.start_time = time.time()\n",
    "        self.start_time_str = time.strftime('%Y%m%d%H%M%S', time.localtime(self.start_time))\n",
    "\n",
    "        if log_path is None:\n",
    "            # 当前文件路径 的当前路径\n",
    "            self.log_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '.'))\n",
    "        else:\n",
    "            self.log_path = log_path\n",
    "\n",
    "        self.log_file_path = os.path.join(self.log_path, 'OperationLog-{}.log'.format(self.start_time_str))\n",
    "        # 日志创建设置\n",
    "        logger_set(path=self.log_file_path, f_level='DEBUG', s_level='INFO', name=\"main\")\n",
    "\n",
    "        self.logger = logging.getLogger('main')\n",
    "        self.logger.info('Log Path:{}'.format(self.log_file_path))\n",
    "\n",
    "        self.ctrl = False\n",
    "        self.alt = False\n",
    "        self.shift = False\n",
    "        self.stop = False\n",
    "\n",
    "        mouse_con = mouse.Controller()\n",
    "\n",
    "        # 鼠标原位置\n",
    "        raw_pos = mouse_con.position\n",
    "        mouse_con.move(50000, 50000)\n",
    "        self.logger.info('屏幕鼠标分辨率： {}'.format(mouse_con.position))\n",
    "        mouse_con.position = raw_pos\n",
    "\n",
    "        # 鼠标监听  自定义开始、结束\n",
    "        self.mouse_listener = mouse.Listener(on_move=self.on_move, on_click=self.on_click, on_scroll=self.on_scroll)\n",
    "        self.keyboard_listener = keyboard.Listener(on_press=self.on_press, on_release=self.on_release)\n",
    "        self.hot_keys_listener = keyboard.GlobalHotKeys({'<ctrl>+<alt>+x': self.ghost_stop})\n",
    "\n",
    "        self.mouse_listener.start()\n",
    "        self.keyboard_listener.start()\n",
    "        self.hot_keys_listener.start()\n",
    "\n",
    "        while not self.stop:\n",
    "            time.sleep(10)\n",
    "\n",
    "    # 鼠标移动\n",
    "    def on_move(self, x, y):\n",
    "        # self.logger.debug('Pointer moved to {}'.format((x, y)))\n",
    "        pass\n",
    "\n",
    "    # 鼠标滚轮\n",
    "    def on_scroll(self, x, y, dx, dy):\n",
    "        self.logger.info('S {:^6s} at ( {} {} )'.format('down' if dy < 0 else 'up', x, y))\n",
    "\n",
    "    # 鼠标按键\n",
    "    def on_click(self, x, y, button, pressed):\n",
    "        self.logger.info('{} {:^6s} at ( {} {} )'.format('O' if pressed else 'X', button.name, x, y))\n",
    "\n",
    "    # 按下键盘\n",
    "    def on_press(self, key):\n",
    "\n",
    "        ctrl_alt_shift = ''\n",
    "        if self.ctrl:\n",
    "            ctrl_alt_shift += '<Ctrl>'\n",
    "        if self.alt:\n",
    "            ctrl_alt_shift += '<Alt>'\n",
    "        if self.shift:\n",
    "            ctrl_alt_shift += '<Shift>'\n",
    "\n",
    "        # 特殊按键\n",
    "        if isinstance(key, keyboard.Key):\n",
    "            self.logger.info('O {:^6s} key [{}]  ({})'.format('spe', key.name, ctrl_alt_shift))\n",
    "\n",
    "            if key.name in ['ctrl_l', 'ctrl_r', 'ctrl']:\n",
    "                self.ctrl = True\n",
    "            if key.name in ['alt_l', 'alt_r', 'alt']:\n",
    "                self.alt = True\n",
    "            if key.name in ['shift_l', 'shift_r', 'shift']:\n",
    "                self.shift = True\n",
    "\n",
    "        # 字母、数字按键\n",
    "        else:\n",
    "            key_str = self.key_code[key.vk] if key.vk in self.key_code else 'Null'\n",
    "            self.logger.info('O {:^6s} key [{}] \"{}\"  ({})'.format('alp', key_str, key.char, ctrl_alt_shift))\n",
    "\n",
    "    # 松开键盘\n",
    "    def on_release(self, key):\n",
    "        ctrl_alt_shift = ''\n",
    "        if self.ctrl:\n",
    "            ctrl_alt_shift += '<Ctrl>'\n",
    "        if self.alt:\n",
    "            ctrl_alt_shift += '<Alt>'\n",
    "        if self.shift:\n",
    "            ctrl_alt_shift += '<Shift>'\n",
    "\n",
    "        # 特殊按键\n",
    "        if isinstance(key, keyboard.Key):\n",
    "            self.logger.info('X {:^6s} key [{}]  ({})'.format('spe', key.name, ctrl_alt_shift))\n",
    "\n",
    "            if key.name in ['ctrl_l', 'ctrl_r', 'ctrl']:\n",
    "                self.ctrl = False\n",
    "            if key.name in ['alt_l', 'alt_r', 'alt']:\n",
    "                self.alt = False\n",
    "            if key.name in ['shift_l', 'shift_r', 'shift']:\n",
    "                self.shift = False\n",
    "\n",
    "        # 字母、数字按键\n",
    "        else:\n",
    "            key_str = self.key_code[key.vk] if key.vk in self.key_code else 'Null'\n",
    "            self.logger.info('X {:^6s} key [{}] \"{}\"  ({})'.format('spe', key_str, key.char, ctrl_alt_shift))\n",
    "\n",
    "    # 按下 <ctrl>+<alt>+x 结束监控\n",
    "    def ghost_stop(self):\n",
    "        self.mouse_listener.stop()\n",
    "        self.keyboard_listener.stop()\n",
    "        self.hot_keys_listener.stop()\n",
    "\n",
    "        self.stop = True\n",
    "        self.logger.warning('GHOST STOP!')\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2020-02-12 21:27:52,244 INFO    : Log Path:C:\\Users\\vincent\\OperationLog-20200212212752.log\n",
      "2020-02-12 21:27:52,245 INFO    : 屏幕鼠标分辨率： (1535, 863)\n",
      "2020-02-12 21:27:52,378 INFO    : X  spe   key [enter]  ()\n",
      "2020-02-12 21:27:52,388 INFO    : X  spe   key [shift_r]  ()\n",
      "2020-02-12 21:27:57,918 INFO    : O  left  at ( 1081 1062 )\n",
      "2020-02-12 21:27:57,983 INFO    : X  left  at ( 1081 1062 )\n",
      "2020-02-12 21:27:58,694 INFO    : O  left  at ( 1110 560 )\n",
      "2020-02-12 21:27:58,766 INFO    : X  left  at ( 1110 560 )\n",
      "2020-02-12 21:28:00,011 INFO    : O  spe   key [shift]  ()\n",
      "2020-02-12 21:28:00,248 INFO    : O  alp   key [A] \"A\"  (<Shift>)\n",
      "2020-02-12 21:28:00,372 INFO    : X  spe   key [A] \"A\"  (<Shift>)\n",
      "2020-02-12 21:28:00,656 INFO    : X  spe   key [shift]  (<Shift>)\n",
      "2020-02-12 21:28:01,086 INFO    : O  spe   key [ctrl_l]  ()\n",
      "2020-02-12 21:28:01,323 INFO    : O  alp   key [A] \"\u0001\"  (<Ctrl>)\n",
      "2020-02-12 21:28:01,472 INFO    : X  spe   key [A] \"\u0001\"  (<Ctrl>)\n",
      "2020-02-12 21:28:01,484 INFO    : X  spe   key [ctrl_l]  (<Ctrl>)\n",
      "2020-02-12 21:28:02,221 INFO    : O  spe   key [ctrl_l]  ()\n",
      "2020-02-12 21:28:02,231 INFO    : O  spe   key [alt_l]  (<Ctrl>)\n",
      "2020-02-12 21:28:02,593 INFO    : O  alp   key [A] \"None\"  (<Ctrl><Alt>)\n",
      "2020-02-12 21:28:02,736 INFO    : X  spe   key [A] \"None\"  (<Ctrl><Alt>)\n",
      "2020-02-12 21:28:02,763 INFO    : X  spe   key [alt_l]  (<Ctrl><Alt>)\n",
      "2020-02-12 21:28:02,773 INFO    : X  spe   key [ctrl_l]  (<Ctrl>)\n",
      "2020-02-12 21:28:11,456 INFO    : O  alp   key [1] \"1\"  ()\n",
      "2020-02-12 21:28:11,560 INFO    : X  spe   key [1] \"1\"  ()\n",
      "2020-02-12 21:28:12,033 INFO    : O  alp   key [2] \"2\"  ()\n",
      "2020-02-12 21:28:12,076 INFO    : X  spe   key [2] \"2\"  ()\n",
      "2020-02-12 21:28:13,150 INFO    : S  down  at ( 1075 558 )\n",
      "2020-02-12 21:28:13,486 INFO    : S  down  at ( 1075 559 )\n",
      "2020-02-12 21:28:13,742 INFO    : S   up   at ( 1075 561 )\n",
      "2020-02-12 21:28:13,782 INFO    : S   up   at ( 1075 561 )\n",
      "2020-02-12 21:28:13,982 INFO    : S  down  at ( 1075 561 )\n",
      "2020-02-12 21:28:14,038 INFO    : S  down  at ( 1075 561 )\n",
      "2020-02-12 21:28:14,902 INFO    : O  spe   key [ctrl_l]  ()\n",
      "2020-02-12 21:28:14,938 INFO    : O  spe   key [alt_l]  (<Ctrl>)\n",
      "2020-02-12 21:28:15,762 INFO    : O  alp   key [X] \"None\"  (<Ctrl><Alt>)\n",
      "2020-02-12 21:28:15,763 WARNING : GHOST STOP!\n"
     ]
    }
   ],
   "source": [
    "og = OperationGhost(log_path=os.getcwd())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "### 鼠标操作器"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(304, 478)\n",
      "(304, 478)\n",
      "(303, 478)\n",
      "(455, 473)\n",
      "(849, 449)\n",
      "(849, 449)\n",
      "(849, 449)\n",
      "(884, 479)\n",
      "(1047, 508)\n",
      "(1300, 547)\n",
      "屏幕鼠标分辨率： (1535, 863)\n",
      "The current pointer position is (1535, 863)\n",
      "20200212 - 212954\n",
      "20200212 - 213000\n"
     ]
    }
   ],
   "source": [
    "import random\n",
    "from pynput.mouse import Button, Controller\n",
    "mouse = Controller()\n",
    "\n",
    "# 循环查看鼠标位置\n",
    "for i in range(10):\n",
    "    print(mouse.position)\n",
    "    time.sleep(0.5)\n",
    "\n",
    "mouse.move(50000, 50000)\n",
    "print('屏幕鼠标分辨率： {}'.format(mouse.position))\n",
    "\n",
    "# 查询鼠标位置\n",
    "print('The current pointer position is {0}'.format(mouse.position))\n",
    "\n",
    "for i in range(2):\n",
    "    print(time.strftime('%Y%m%d - %H%M%S', time.localtime(time.time())))\n",
    "    time.sleep(random.random()*5 + 5)\n",
    "    \n",
    "    if random.random() > 0.5:\n",
    "        time.sleep(random.random())\n",
    "        # 设置鼠标位置\n",
    "        mouse.position = (1400, 500)\n",
    "        mouse.press(Button.left)\n",
    "        mouse.release(Button.left)          \n",
    "        mouse.scroll(0, 1000*(random.random()-0.5))\n",
    "    if random.random() > 0.5:\n",
    "        time.sleep(random.random())\n",
    "        # 设置鼠标位置\n",
    "        mouse.position = (1400, 500)\n",
    "        mouse.press(Button.left)\n",
    "        mouse.release(Button.left)        \n",
    "        mouse.scroll(0, 2000*(random.random()-0.5))\n",
    "    if random.random() > 0.5:\n",
    "        time.sleep(random.random())\n",
    "        # 设置鼠标位置\n",
    "        mouse.position = (1400, 500)\n",
    "        mouse.press(Button.left)\n",
    "        mouse.release(Button.left)         \n",
    "        mouse.scroll(0, 2000*(random.random()-0.5))\n",
    "        "
   ]
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "kernelspec": {
   "display_name": "Python [conda env:Anaconda3]",
   "language": "python",
   "name": "conda-env-Anaconda3-py"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
